package org.hzero.business;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author: tianhao.luo@hand-china.com 2021/7/5  下午3:09
 */
public class KnifeRedisUtils {

    /**
     * 使用volatile是为了避免指令重排序
     */
    private static volatile JedisPool jedisPool;
    /**
     * 服务器IP地址
     */
    private static String ADDR = KnifePropertyUtil.getSpecialValueByKey(KnifePropertyUtil.getValueByKey(RedisConfig.IP, KnifeRedisUtils.class));
    /**
     * 密码
     */
//    private static String AUTH = PropertyUtil.getSpecialValueByKey(PropertyUtil.getValueByKey("cas.ticket.registry.redis.password",RedisUtils.class));
    /**
     * 端口
     */
    private static int PORT = Integer.valueOf(KnifePropertyUtil.getSpecialValueByKey(KnifePropertyUtil.getValueByKey(RedisConfig.PORT, KnifeRedisUtils.class)));
    /**
     * 数据库
     */
    private static int DB = Integer.valueOf(KnifePropertyUtil.getSpecialValueByKey(KnifePropertyUtil.getValueByKey(RedisConfig.DB, KnifeRedisUtils.class)));
    /**
     * 连接实例的最大连接数
     */
    private static int MAX_ACTIVE = Integer.valueOf(KnifePropertyUtil.getValueByKey(RedisConfig.MAX_ACTIVE, KnifeRedisUtils.class));
    /**
     * 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
     */
    private static int MAX_IDLE = Integer.valueOf(KnifePropertyUtil.getValueByKey(RedisConfig.MAX_IDLE, KnifeRedisUtils.class));
    /**
     * 控制一个pool最少有多少个状态为idle(空闲的)的jedis实例，默认值也是0。
     */
    private static int MIN_IDLE = Integer.valueOf(KnifePropertyUtil.getValueByKey(RedisConfig.MIN_IDLE, KnifeRedisUtils.class));
    /**
     * 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException
     */
    private static int MAX_WAIT = Integer.valueOf(KnifePropertyUtil.getValueByKey(RedisConfig.MAX_WAIT, KnifeRedisUtils.class));
    /**
     * 连接超时的时间
     */
    private static int TIMEOUT = Integer.valueOf(KnifePropertyUtil.getValueByKey(RedisConfig.TIME_OUT, KnifeRedisUtils.class));
    /**
     * 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
     */
    private static boolean TEST_ON_BORROW = true;

    /**
     * redis连接配置
     */
    interface RedisConfig{
        /**
         * IP
         */
        String IP = "redis.ip";
        /**
         * 端口
         */
        String PORT = "redis.port";
        /**
         * s
         */
        String DB = "redis.db";
        /**
         * 连接池最大连接数（使用负值表示没有限制）
         */
        String MAX_ACTIVE="redis.pool.maxActive";
        /**
         * 连接池最大空闲连接
         */
        String MAX_IDLE="redis.pool.maxIdle";
        /**
         * 连接池最大阻塞等待时间
         */
        String MAX_WAIT="redis.pool.maxWait";
        /**
         * 连接池最小空闲连接
         */
        String MIN_IDLE="redis.pool.minIdle";
        /**
         * 超时时间
         */
        String TIME_OUT="redis.pool.timeout";
    }


    /**
     * 获取jedis连接
     * @return jedis连接
     */
    public static Jedis getJedis() {
        if (jedisPool == null){
            // 将锁移动到此处，避免因为多线程获取jedis连接时，频繁加锁
            synchronized (JedisPool.class){
                // 如果一个线程获取锁，创建单例，另一个线程等待获取锁，第一个线程结束了，创建单例，结束了，
                // 第二个线程获取到锁，此时单例对象已经创建了，如果不判空，依然会继续创建
                if(jedisPool == null){
                    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                    jedisPoolConfig.setMaxTotal(MAX_ACTIVE);
                    jedisPoolConfig.setMaxIdle(MAX_IDLE);
                    jedisPoolConfig.setMinIdle(MIN_IDLE);
                    jedisPoolConfig.setMaxWaitMillis(MAX_WAIT);
                    jedisPoolConfig.setTestOnBorrow(TEST_ON_BORROW);
                    jedisPool = new JedisPool(jedisPoolConfig, ADDR, PORT, TIMEOUT, null, DB);
                }
            }
        }
        return jedisPool.getResource();
    }
}
